package main

import (
	"C"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"sync"
	"time"
)

type Func func(key string) (interface{}, error)

type Memo1 struct {
	f Func
	cache map[string] result
}

type result struct {
	value interface{}
	err error
}

func New1(f Func) *Memo1 {
	return &Memo1{f: f, cache: make(map[string] result)}
}

func(memo *Memo1) Get(key string) (interface{}, error) {
	res, ok := memo.cache[key]
	if !ok {
		res.value, res.err = memo.f(key)
		memo.cache[key] = res
	}
	return res.value, res.err
}

func main()  {
	m := New1(httpGetBody)
	urls := []string{
		"https://www.baidu.com/",
		"https://element.eleme.io/#/zh-CN",
		"http://www.moe.gov.cn/",
		"https://www.baidu.com/",
		"http://www.moe.gov.cn/",
		"https://element.eleme.io/#/zh-CN",
		"http://www.moe.gov.cn/",
		"https://www.baidu.com/",
	}
	//for _, url := range urls {
	//	start := time.Now()
	//	value, err := m.Get(url)
	//	if err != nil {
	//		log.Print(err)
	//	}
	//	fmt.Printf("%s, %s, %d bytes\n", url,
	//		time.Since(start), len(value.([]byte)))
	//}

	var n sync.WaitGroup
	for _, url := range urls {
		n.Add(1)
		go func() {
			start := time.Now()
			value, err := m.Get(url)
			if err != nil {
				log.Print(err)
			}
			fmt.Printf("%s, %s, %d bytes\n", url,
				time.Since(start), len(value.([]byte)))
			n.Done()
		}()
	}
	n.Wait()
}

func httpGetBody(url string) (interface{}, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}